package com.demo.starter.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.yaml.snakeyaml.util.ArrayUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 日志拦截器
 * @author cyj
 **/
@Slf4j
@Aspect
@Configuration
public class WebLogAop {

    private ThreadLocal<Long> local = new ThreadLocal<>();

    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void webLog() {}

    @Before("webLog()")
    public void before(JoinPoint joinPoint) {
        local.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        //log 请求内容
        String className = joinPoint.getSignature().getDeclaringTypeName();
        log.info("执行的类名: ({} 方法：{})",
                className.substring(className.lastIndexOf(".") + 1) + ".java", joinPoint.getSignature().getName());

        // 去除Request或者Response对象
        Object[] joinPointArgs = joinPoint.getArgs();
        Stream<?> stream =  joinPointArgs == null ? Stream.empty() : Arrays.stream(joinPointArgs);
        List<Object> logArgs = stream.filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)))
                .collect(Collectors.toList());
        log.info("请求url:  {} {}， 参数: {}", request.getRequestURL().toString(), request.getMethod(),
                JSON.toJSONString(logArgs));
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) {
        Long startTime = local.get();
        remove();
        String retStr = JSON.toJSONString(ret, SerializerFeature.IgnoreNonFieldGetter);
        log.info("返回结果：{}, 耗时：{}", retStr, System.currentTimeMillis() - startTime);
    }

    @AfterThrowing(throwing="ex", pointcut = "webLog()")
    public void doAfterThrowing(Throwable ex) {
        log.error("AfterThrowing处理", ex);
        remove();
    }

    private void remove() {
        local.remove();
    }
}
